package server;

import java.net.*;
import java.io.*;
import networking.DBconnector;

public class Worker implements Runnable {

    private Socket client;
    private Thread thread;
    private String[] parseInfo;
    private int clientPort;
    private String request;
    private Server parent;
    private DBconnector db;
    private BufferedReader inFromClient;
    private DataOutputStream outToClient;

    Worker(Server p, Socket c, DBconnector dab) {
        parent = p;
        System.out.println("Worker thread initialization");
        client = c;
        parseInfo = null;
        clientPort = client.getPort();
        db = dab;
    }


    /*
     * Start the worker thread.
     */
    public void start() {
        System.out.println("Worker thread start");
        thread = new Thread(this);
        thread.start();
    }

    /*
     * Parse a request string into an array of Strings.
     */
    public void setParseInfo(String toParse) {
        String temp = toParse.substring(1, toParse.length() - 1);
        parseInfo = temp.split("><");
    }

    /*
     * Get Array of Strings representing request.
     */
    public String[] getParseInfo() {
        return parseInfo;
    }

    /*
     * Get the request type of a particular array of Strings.
     */
    public String getRequestType() {
        if (parseInfo == null) {
            return null;
        }
        return getParseInfo()[0];

    }

    /*******************************REQUESTS AND RESPONSES*******************
    Client requests:

    - <create><password><first name><last name><birthdate><email>
    - <login><email><password>
    - <logout><user id>
    - <addcomment><game id><user id><date added><time added><comment>
    - <addbet><game id><user id><date added><time added><bet amount>
    - <getgames><field><key><isInt>
    // where fields: 1 = id, 2 = home team, 3 = away team, 4 = location, 5 = startdate, 7 = referee
    // isInt to differentiate if key is an int or a String (fields 1, 2, 3 need an int, fields 4, 5 and 7 need a String)
    // this is important for the server when parsing the big string because there are two different overloaded functions (see below for more details)
    - <getallgames><field>   // sorted by date if field = 1, by location if field = 4, or by referee if field = 7
    - <getcomments><field><key>   //fields: commentID (field = 1), userID (field = 2), or game (field = 3)
    - <getbets><field><key>   // fields: betID = 1, game = 2, user = 3, dateadded = 4
    - <getlastncomments><n>   // used on the homepage to display the last n comments. n is the number of most recent comments requested.
    - <getlastnbets><n>   // used on the homepage to display the last n bets. n is the number of most recent bets requested.
    - more functions to be added later for extra features (like displaying team group info, and the tree-brackets cup info)

    Server responses:

    <create> --->
    <user><id><first name><last name><birthday><email>
    or
    <error><could not create user>

    <login> ---->
    <user><id><first name><last name><birthday><email>
    or
    <error><not registered>

    <logout> ---->
    //not decided

    <addcomment> ---->
    <comment><1><comment id><user's first and last name><date added><time added><text content>
    or
    <error><could not create comment>

    <addbet> ----->
    <bet><1><bet id><game id><user's first and last name><date added><time added><type><status><bet amount> //Type is win/draw/lose
    or
    <error><could not create bet>

    <getgames> ----> (Note: Key selects the subset of games we want)
    <game><n><id # 1><team><team2><location><startdate><gametime><referee><score1><score2><events><id # 2><team><team2><location><startdate><gametime><referee><score1><score2><events>...<id # n><team><team2><location><startdate><gametime><referee><score1><score2><events>
    or
    <error><could not select games>

    <getallgames> ---->
    //same as getgames

    <getcomments> ----->
    <comment><n><comment #1 id><user's first and last name><date added><time added><text content>...<comment #n id><username><date added><time added><text content>
    or
    <error><could not get comments>

    <getlastncomments> --->
    //same as getcomments but not specific to user id
    or
    <error><could not get comments>

    <getbets> ----> (for user profile?)
    <bet><n><bet #1 id><game id><user's first and last name><date added><time added><status><bet amount>...<bet #n id><game id><user's first and last name><date added><time added><status><bet amount>
    or
    <error><could not get bets>

    <getlastnbets><n>
    //same as getbets but not specific to user bets
    or
    <error><could not get bets>


    - To be added later: getTeamInfo
     */

    /**
     * General handle result function
     */
    public String handleResult() {
        String type = getRequestType();
        String result = null;

        System.out.println("Type is: " + type);

        if (type.equals("create")) {
            System.out.println("CREATE!!!");
            result = create();
            System.out.println(result);
        }

        else if (type.equals("login")) {
            result = login();
        }

        else if (type.equals("logout")) {
            result = logout();
        }

        else if (type.equals("addcomment")) {
            result = addComment();
        }

        else if (type.equals("addbet")) {
            result = addBet();
        }
        else if (type.equals("getgames")) {
            result = getGames();
        }

        else if (type.equals("getallgames")) {
            result = getAllGames();
        }

        else if (type.equals("getbets")) {
            result = getBets();
        }

        else if (type.equals("getlastncomments")) {
            result = getLastNComments();
        }

        else if (type.equals("getlastnbets")) {
            result = getLastNBets();

        }

        else if (type.equals("getteaminfo")) {
            result = getTeamInfo();
        }

        else if (type.equals("getgroupinfo")) {
            result = getGroupInfo();
        }

        else if (type.equals("test")) {
            result = "TESTING SERVER";
        }

        else {
            result = "<error><could not parse request>";
        }

        System.out.println("Result: "+result);

        return result;
    }

    /**
     * Create User response. Request is:
     * <create><password><first name><last name><birthdate><email>
     *
     * Works.
     *
     */
    public String create() {
        int success = 0;
        success = db.addUser(parseInfo[1], parseInfo[2], parseInfo[3],
                parseInfo[4], parseInfo[5]);
        if (success != 0) {
            return "<user id>" + "<" + Integer.toString(success) + ">";

        } else {
            return "<error><could not create user>";
        }
    }

    /**
     * Login request
     * Client sends username and password
     * Return ok or error according to whether user is registered
     * or not
     *
     * Works!
     */
    public String login() {
        int isRegistered = 0;

        isRegistered = db.searchUser(parseInfo[1], parseInfo[2]);
        if (isRegistered != 0) {

            return db.getUser(isRegistered);
        } else {
            return "<error><not registered>";
        }
    }

    /**
     * Logout request
     *
     * Not decided yet
     */
    public String logout() {

        /*
         * Set logged off in database
         */
        return "ok";
    }

    /**
     *Add a comment to the database, returns the id of the comment
     *<comment><1><comment id><user's first and last name><date added><time added>
     * <text content>
     *
     * Works!
     */
    public String addComment() {
        int result = 0;

        result = db.addComment(Integer.parseInt(parseInfo[1]),
                    Integer.parseInt(parseInfo[2]),parseInfo[3],parseInfo[4],parseInfo[5]);
         
        if (result!= 0) {
            return db.getComments(1, result);
        }
        else 
            return "<error><could not add comment>";

    }

    /**
     * Function to create a bet and insert into database. Similar to add
     * comment
     *
     * Works!
     * Must create a type for bets.
     */
    public String addBet() {
        int result = 0;

        result = db.addBet(Integer.parseInt(parseInfo[1]),
                    Integer.parseInt(parseInfo[2]),parseInfo[3],parseInfo[4],
                    Integer.parseInt(parseInfo[5]));
        if (result!=0) {
            return db.getBet(1, result);
        }

        return "<error><could not add comment>";
    }


    /**
     * Game request
     * Client sends request for a game
     *
     * Works!
     *
     */
    public String getGames() {


        String result = "<error><could not retrieve games>";
        String parsed[] = getParseInfo();
        for(String e: parsed) {
            System.out.println(e);
        }
        if (parsed[3].equals("false")) {
            result = db.getGames(Integer.parseInt(parsed[1]), parsed[2]);
        } else if (parsed[3].equals("true")) {
            result = db.getGames(Integer.parseInt(parsed[1]), Integer.parseInt(parsed[2]));
        }

//        parsed = result.split("><");
//
//        int n = Integer.parseInt(parsed[1]);
//        System.out.println(parsed[1]);
//        int start = 3;
//        String[] results = new String[n];
//        for (int i = 0; i<n; i++) {
//            results[i] = parsed[start]+"-"+parsed[start+1];
//            start+=11;
//        }
//
//        for (String x: results) {
//            System.out.println(x);
//        }

        return result;
    }

    /**
     * Get All Games sorted by field.
     *
     * Works!
     *
     */
    public String getAllGames() {
        String result = "<error><could not retrieve games>";
        result = db.getAllGames(Integer.parseInt(getParseInfo()[1]));
        return result;

    }

    /**
     * Get Bets sorted by field
     */
    public String getBets() {
        String result = "<error><could not retrieve bets>";
        result = db.getBet(Integer.parseInt(getParseInfo()[1]),
                Integer.parseInt(getParseInfo()[2]));
        System.out.println(result);
        return result;
    }

    /**
     * Get Last N comments for all users. 
     *
     * Works!
     */
    public String getLastNComments() {
        String result = "<error><could not retrieve comments>";
        result = db.getLastNComments(Integer.parseInt(getParseInfo()[1]));
        if (result == null) {
            result = "<error><Do not have "+Integer.parseInt(getParseInfo()[1])+" " +
                    "comments>";
        }
        return result;
        
    }

    /**
     * Get Last N bets for all users.
     *
     * Works!
     */
    public String getLastNBets() {
        String result = "<error><could not retrieve bets>";
        result = db.getLastNBets(Integer.parseInt(getParseInfo()[1]));
        if (result == null) {
            result = "<error><Do not have "+Integer.parseInt(getParseInfo()[1])+" " +
                    "bets>";
        }
        return result;

    }

    /**
     * Get Team Info by team number.
     *
     */

    public String getTeamInfo() {
        String result = "<error><could not retrieve team info>";
        result = db.getTeamInfo(Integer.parseInt(getParseInfo()[1]));
        return result;

    }

    /**
     * Get Group info by Groupletter
     * 
     */
    public String getGroupInfo() {
        String result = "<error><could not retrieve group info>";
        result = db.getGroupInfo(getParseInfo()[1]);
        return result;
    }



    /**
     *
     * General run method of the thread.
     * Accept data from socket and process it.
     * Processing involved:
     *  - Process login request and login client
     *  - Register new users into user database.
     *  - Enter new users into database
     *  - Process game requests and serve game data
     *  - Store comments into database
     *
     */
    public void run() {
        try {
            System.out.println("In runnable");
            inFromClient = new BufferedReader(
                    new InputStreamReader(client.getInputStream()));
            outToClient =
                    new DataOutputStream(client.getOutputStream());

            request = inFromClient.readLine();
            setParseInfo(request);
            System.out.println("Parsed stuff");



            String result = null;

            System.out.println("Handling result");
            result = handleResult();

            System.out.println("Handled result");

            outToClient.writeBytes(result);

            System.out.println("Wrote stuff");
            inFromClient.close();
            outToClient.close();
            client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
